Skip to content

refactor: pre-M4 protocol cleanup — ACP path unification, legacy removal, type safety - #147

Merged
Leoyzen merged 36 commits into
refactor/agentwolf_v1from
feature/pre-m4-protocol-cleanup
Jul 13, 2026
Merged

refactor: pre-M4 protocol cleanup — ACP path unification, legacy removal, type safety#147
Leoyzen merged 36 commits into
refactor/agentwolf_v1from
feature/pre-m4-protocol-cleanup

Conversation

@Leoyzen

@Leoyzen Leoyzen commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR implements the pre-M4 protocol cleanup — 22 implementation tasks across 4 phases that eliminate ACP dual-path execution, remove legacy enums/fields, improve type safety, and wire up event system gaps before the M4 multi-config milestone.

What changed

Phase 1: ACP Execution Path Unification (T0-T6)

  • V10 snapshot baseline: Created syrupy snapshot tests capturing ACP streaming event sequences
  • ACPAgentAPI adapter: Added stream_events() and get_messages() methods with @runtime_checkable protocols
  • ACPTurn delegation: Replaced 200-LOC inline _stream_events() with thin delegate to ACPTurn.execute()
  • Hook firing cleanup: Removed ACP-specific hook branches from _run_stream_once(), removed hooks_fired double-fire guard (replaced with per-Turn _logged_tools set)
  • Unified prompt routing: Removed ACP-specific queue_prompt/inject_prompt branching — all agents now use session_pool.followup()/steer()

Phase 2: Legacy Field & API Cleanup (T7-T13)

  • MCPManager API: Renamed _SessionContextMcpSessionContext (public), added MCPManager.add_transport()
  • ACPSession MCP migration: initialize_mcp_servers() now uses MCPManager methods instead of mutating agent fields
  • NativeAgent field removal: Removed _mcp_snapshot and _session_connection_pool fields
  • CommChannel typing: Added deliver_feedback() to protocol (returns bool), removed duck-typing
  • HostContext.pool removal: Removed pool escape hatch from HostContext, migrated all access sites to _agent_pool
  • RunStatus removal: Replaced RunStatus enum with RunOutcome (COMPLETED/FAILED/CHECKPOINTED) + RunState (IDLE/RUNNING/DONE)
  • Dead code removal: Removed unreachable code in session_controller.py

Phase 4: Type Safety & Code Quality (T14-T19)

  • type: ignore removal: Removed all 6 type: ignore[attr-defined] in run.py by holding direct dimension refs
  • set_replaying(): Added to CommChannel protocol, replaced direct _replaying attribute access
  • publishes_to_event_bus property: Replaced _channel_publishes_to_event_bus isinstance check with protocol property
  • hasattr replacement: Replaced hasattr patterns with is_busy property and isinstance checks
  • Exception narrowing: Replaced 3 generic except Exception clauses in ACPTurn with specific exception types
  • RunHandle.start() decomposition: Decomposed 397-SLOC method into 5 sub-methods each < 100 SLOC

Phase 6: Event System Gaps (T20-T22)

  • McpToolsChangedEvent: Wired emission from MCPCapability.on_change()EventProcessor → SSE broadcast
  • Cancellation distinction: EventProcessor now emits SessionStatusEvent(status="cancelled") for cancelled streams
  • stream_adapter cleanup: Removed deprecated _handle_event method, updated tests to use EventProcessor directly

Verification

  • uv run ruff check src/ — All checks passed
  • uv run --no-group docs mypy src/ — 0 errors in 607 source files
  • uv run pytest tests/integration/test_acp_streaming.py -m acp_snapshot — 2/2 snapshots pass
  • ✅ 2218+ tests pass (3 pre-existing failures unrelated to this PR)
  • ✅ All 10 grep verification gates pass (hooks_fired, _SessionContext, RunStatus, host_context.pool, etc.)

Scope

In scope: Phases 1, 2, 4, 6 (22 tasks) + V10 snapshot baseline + F1-F4 verification

Out of scope (deferred):

  • Phase 7 (10 optional tasks — stay in OpenSpec)
  • Phase 3 (OpenCode server hardening — merged into M4)
  • Phase 5 (M4 identity preparation — merged into M4)
  • AgentWolf rename, subagent_display_mode removal, M4 implementation

Commits

35 commits, one per task + fix commits for type/lint issues discovered during verification.

Leoyzen added 30 commits July 13, 2026 11:12
Replace all _run_stream_once references in tests with _stream_events,
which is the public entry point that will survive T2's refactor (it
will delegate to ACPTurn.execute internally).

10 test files updated:
- 5 with active mock updates (test_run_stream_direct_gating,
  test_auto_resume_message_redflag, test_session_scoped_consumer,
  test_session_pool_input_provider, test_session_lifecycle)
- 5 with comment/name-only updates (test_run_lifecycle,
  test_base_agent_run_v2, test_inject_prompt_cross_task,
  test_capability_hooks_standalone, test_cancelled_message)

Verification:
- grep -rn '_run_stream_once' tests/ returns 0 matches
- 65 tests pass across all modified files
- V10 snapshot tests pass (2/2)
Migrate all HostContext.pool access sites to use MessageNode._agent_pool
directly, then remove the pool field from HostContext and the pool=self
argument from AgentPool.get_context().

Source changes:
- context.py: Remove pool field, AgentPool import, and Any import
- pool.py: Remove pool=self from HostContext constructor
- base_team.py: Use _agent_pool instead of host_context.pool (2 sites)
- state.py: Use agent._agent_pool instead of _ctx.pool
- agent_routes.py: Use state.agent._agent_pool instead of ctx.pool
- acp_agent.py: Use default_agent._agent_pool instead of ctx.pool (4 sites)
- native_agent/agent.py: Use self._agent_pool instead of ctx.pool (2 sites)

Test changes:
- Remove pool back-reference tests from test_pool_get_context.py and test_context.py
- Update conftest.py and 10+ test files to set _agent_pool instead of pool.pool
- Remove get_context mock from test_team_member_skills.py
- Remove ctx.pool from test_factory.py
…re cluster

- Update test_steer_direct_channel to verify deliver_feedback returns False
- Update test_session_migration for publishes_to_event_bus property
- Append T15 learnings to notepad
- Remove unused message_history param from ACPTurn.__init__ (dead code)
- Cast self._api to ACPClientProtocol in acp_agent.py call sites
- Fix status annotation from str to SessionStatusType in event_processor.py
- Clean up stale # type: ignore comments
- Update tests to match ACPTurn constructor changes

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a comprehensive cleanup of technical debt across the ACP server, OpenCode server, and shared orchestration infrastructure, establishing a stable baseline for M4 (multi-config) development. Key changes include unifying ACP execution paths through Turn.execute(), refactoring RunHandle.start() into composable sub-methods, removing the RunStatus enum in favor of RunState and RunOutcome, and cleaning up legacy MCP lifecycle state management. I have addressed the reviewer's feedback regarding the Gantt chart dates and the encapsulation of _agent_pool access.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread docs/rfcs/draft/RFC-0053-pre-m4-protocol-debt-cleanup.md

for agent in self.iter_agents():
pool = agent.host_context.pool if agent.host_context else None
pool = agent._agent_pool

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accessing the private member _agent_pool directly violates encapsulation. While this change is part of removing the HostContext.pool escape hatch, it introduces another form of tight coupling. Consider adding a public property for _agent_pool on MessageNode if it's intended to be accessed by other modules, or refactoring this logic to avoid direct access to the agent's internal pool reference.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid concern. This is a known trade-off from T11 (removing HostContext.pool).

Context: MessageNode.agent_pool property already exists but emits DeprecationWarning. T11 removed HostContext.pool (the escape hatch), so all access sites migrated to _agent_pool. The proper fix is to un-deprecate the agent_pool property now that HostContext.pool is gone — agent_pool is no longer a deprecated escape hatch but the only public interface.

This un-deprecation is out of scope for this PR. Tracked as follow-up tech debt. The current _agent_pool access is a pragmatic interim solution that avoids triggering deprecation warnings in production code.

Leoyzen added 4 commits July 13, 2026 14:44
… as TODO

- Add TODO(m4) comment at base_team.py:411 explaining _agent_pool usage
- Add M4 tasks 14.8-14.11 for NodeContext.pool→host migration:
  - 14.8: Add input_provider to HostContext
  - 14.9: Migrate NodeContext.pool → NodeContext.host
  - 14.10: Move get_skill_instructions_for_node() to SkillsManager
  - 14.11: Audit protocol server _agent_pool refs
@Leoyzen
Leoyzen force-pushed the feature/pre-m4-protocol-cleanup branch from f68e745 to a3af80d Compare July 13, 2026 07:11
@Leoyzen
Leoyzen merged commit 814398c into refactor/agentwolf_v1 Jul 13, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant